package managedbean;

import bean.managed.ContactEntityController;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;
import com.sun.mail.smtp.*;
import entity.SystemUserEntity;
import java.io.*;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.event.TabChangeEvent;
import org.primefaces.model.UploadedFile;

@ManagedBean(name = "email")
@SessionScoped
public class EmailManagedBean extends AbstractBacking implements Serializable {

    //Instances for sending mail
    private String sender;
    private String to;
    private String cc;
    private String subject;
    private String msgText;
    private UploadedFile file;
    private String status;
    //private Logger logger = LoggerFactory.getLogger(SendMail.class);
    //instances for check mail
    private String username;
    private String emailPassword;
    private String result;
    private boolean login = false;
    private ArrayList<Message> msg;
    private Message selectedMessage;
    @ManagedProperty(value = "#{contactEntityController}")
    private ContactEntityController contactEntityController;
    @ManagedProperty(value = "#{loginBacking}")
    private LoginBacking loginBacking;
    
    public void emptyFields() {
        //empty cache values
        setSender(getCurrentUser().getContact().getEmail());
        setTo("");
        setCc("");
        setSubject("");
        setMsgText("");
        setStatus("");
        contactEntityController.setAddressBook(null);
        contactEntityController.setAddressBookCc(null);
        System.out.println("emptying");
    }

    public void action(TabChangeEvent event) {
        String folderName = event.getTab().getId();
        System.out.println("Accessing Folder: " + folderName);

        if (folderName.equals("inbox")) {
            accessFolder("Inbox");
        }

        if (folderName.equals("sent")) {
            accessFolder("[Gmail]/Sent Mail");
        }

        if (folderName.equals("drafts")) {
            accessFolder("[Gmail]/Drafts");
        }

        if (folderName.equals("trash")) {
            accessFolder("[Gmail]/Trash");
        }

        //empty cache values
        emptyFields();
    }

    public void inboxDeleteMessages(ActionEvent event) {
        deleteMessages(getSelectedMessage(), "Inbox");
    }

    public void sentDeleteMessages(ActionEvent event) {
        deleteMessages(getSelectedMessage(), "[Gmail]/Sent Mail");
    }

    public void draftsDeleteMessages(ActionEvent event) {
        deleteMessages(getSelectedMessage(), "[Gmail]/Drafts");
    }

    public void deleteMessages(Message message, String folderName) {
        try {
            String host = "imap.gmail.com";

            Properties prop = System.getProperties();
            prop.setProperty("mail.store.protocol", "imaps");

            Session mySession = Session.getInstance(prop, null);

            Store store = mySession.getStore("imaps");
            System.out.println("Connecting..." + host + " " + getUsername() + " " + getEmailPassword());
            store.connect(host, getUsername(), getEmailPassword());
            System.out.println("Connected");
            this.setLogin(true);

// Obtain a handle to the inbox.
            Folder folder = store.getFolder(folderName);
            folder.open(Folder.READ_WRITE);
            Folder trash = store.getFolder("[Gmail]/Trash");

            //Deleting
            System.out.println("Deleting: " + message.getSubject() + "...");
            Message[] m = new Message[1];
            m[0] = message;
            folder.copyMessages(m, trash);
            message.setFlag(Flags.Flag.DELETED, true);
            System.out.println("Message Deleted.");

            folder.close(true);
            store.close();
        } catch (Exception e) {
            result = e.getMessage();
        }
    }

    public void sendMail(ActionEvent event) {
        doSend(this.sender, this.to, this.cc, this.subject, this.msgText);
        System.out.println(to);
    }

    public String messageSelect(SelectEvent event) {
        System.out.println("Accessing Message Context");
        return "viewMessage?faces-redirect=true";
    }

    public String draftSelect(SelectEvent event) {
        System.out.println("Opening Saved Draft");
        try {
            setSender((selectedMessage.getFrom())[0].toString());
            setSubject(selectedMessage.getSubject());
            setMsgText((String) selectedMessage.getContent());

            Address[] to = selectedMessage.getRecipients(Message.RecipientType.TO);
            Address[] cc = selectedMessage.getRecipients(Message.RecipientType.CC);

            for (int i = 0; i < to.length; i++) {
                if (i == 0) {
                    setTo(to[i].toString());
                } else {
                    setTo(getTo() + "; " + to[i].toString());
                }
            }

            if (cc != null) {

                for (int j = 0; j < cc.length; j++) {
                    if (j == 0) {
                        setCc(cc[j].toString());
                    } else {
                        setCc(getCc() + "; " + cc[j].toString());
                    }
                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        }
        return "email?faces-redirect=true";
    }

    public void statusUpdate(String status) {
        FacesContext context = FacesContext.getCurrentInstance();
        context.addMessage(null, new FacesMessage(status, null));
    }

    public void accessFolder(String folderName) {

        try {
            String host = "imap.gmail.com";

            Properties prop = System.getProperties();
            prop.setProperty("mail.store.protocol", "imaps");

            Session mySession = Session.getInstance(prop, null);

            Store store = mySession.getStore("imaps");
            System.out.println("Connecting..." + host + " " + getUsername() + " " + getEmailPassword());
            store.connect(host, getUsername(), getEmailPassword());
            System.out.println("Connected");
            this.setLogin(true);

// Obtain a handle to the inbox.
            Folder folder = store.getFolder(folderName);
            folder.open(Folder.READ_WRITE);

// Obtain the messages.
            Message messages[] = folder.getMessages();
            //Message msg;
            msg = new ArrayList<Message>();

            for (int i = messages.length - 1; i >= 0; i--) {
                msg.add(messages[i]);
            }

        } catch (Exception e) {
            result = e.getMessage();
        }
    }

    public void doSend(String sender, String to, String cc, String subject, String msgText) {

        try {
            Properties prop = System.getProperties();
            prop.put("mail.transport.protocol", "smtp");
            prop.put("mail.smtp.host", "mailauth.comp.nus.edu.sg");
            prop.put("mail.smtp.port", "25");
            prop.put("mail.smtp.auth", "true");
            prop.put("mail.smtp.starttls.enable", "true");
            prop.put("mail.smtp.debug", "true");

//Authenticate email and password
            //javax.mail.Authenticator auth = new SmtpAuthenticator();
// Get a handle to the Session.
            Session mySession = Session.getInstance(prop, new javax.mail.Authenticator() {

                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication("eddie@comp.nus.edu.sg", "@qwerty2911");
                }
            });

// Create a Messsage.
            SMTPMessage message = new SMTPMessage(mySession);
// Set the 'from' address.
            message.setFrom(new InternetAddress(sender));

// Set the 'to' and 'cc' addresses.
            StringTokenizer tokensTo = new StringTokenizer(to, ";");
            String addr = "";
            while (tokensTo.hasMoreTokens()) {
                addr = tokensTo.nextToken();
                message.addRecipient(Message.RecipientType.TO,
                        new InternetAddress(addr));
            }
            StringTokenizer tokensCC = new StringTokenizer(cc, ";");
            while (tokensCC.hasMoreTokens()) {
                addr = tokensCC.nextToken();
                message.addRecipient(Message.RecipientType.CC,
                        new InternetAddress(addr));
            }
// Set the 'subject'.
            message.setSubject(subject);

// Set the date the message would be sent.
            message.setSentDate(new Date());

// Handle the attachment, if there is one.
            if (file != null) {
                System.out.println("file processing ....");
                // Set the 'text' as the first body part.
                BodyPart mbp1 = new MimeBodyPart();
                mbp1.setText(msgText);
                Multipart mp = new MimeMultipart();
                mp.addBodyPart(mbp1);

                BodyPart mbp = new MimeBodyPart();
                String imgName = getFile().getFileName().substring(getFile().getFileName().lastIndexOf("\\") + 1);
                System.out.println("file path: " + getFile().getFileName());
                DataSource src = new FileDataSource(getFile().getFileName());
                mbp.setDataHandler(new DataHandler(src));
                mbp.setFileName(imgName);
                mp.addBodyPart(mbp);
                message.setContent(mp);

            } else {
                // Use the default method if no attachment.
                message.setText(msgText);
            }

// Send it.
            SMTPTransport.send(message);
            System.out.println("MessageSent");
            setStatus("Message Sent Sucessfully.");
            statusUpdate(getStatus());
//empty values.
            emptyFields();

        } catch (Exception e) {
            // response.sendRedirect("sendMail.jsp");
            setStatus(e.getMessage());
        }
    }

    public void saveDraft(ActionEvent event) {

        try {

            Properties prop = System.getProperties();
            prop.setProperty("mail.store.protocol", "imaps");

//Authenticate email and password
            //javax.mail.Authenticator auth = new SmtpAuthenticator();
// Get a handle to the Session.
            Session mySession = Session.getInstance(prop, new javax.mail.Authenticator() {

                protected PasswordAuthentication getPasswordAuthentication() {
                    return new PasswordAuthentication(getUsername(), getEmailPassword());
                }
            }); //static as of now, user:staff.merlion@gmail.com pwd:@asdqwe123
// Create a Messsage.
            SMTPMessage message = new SMTPMessage(mySession);

// Set the 'from' address.
            message.setFrom(new InternetAddress(getSender()));

// Set the 'to' and 'cc' addresses.
            StringTokenizer tokensTo = new StringTokenizer(getTo(), ";");
            String addr = "";
            while (tokensTo.hasMoreTokens()) {
                addr = tokensTo.nextToken();
                message.addRecipient(Message.RecipientType.TO,
                        new InternetAddress(addr));
            }
            StringTokenizer tokensCC = new StringTokenizer(getCc(), ";");
            while (tokensCC.hasMoreTokens()) {
                addr = tokensCC.nextToken();
                message.addRecipient(Message.RecipientType.CC,
                        new InternetAddress(addr));
            }

            message.setSubject(getSubject());
            message.setSentDate(new Date());

// Handle the attachment, if there is one.
            if (file != null) {
                System.out.println("file processing ....");
                // Set the 'text' as the first body part.
                BodyPart mbp1 = new MimeBodyPart();
                mbp1.setText(getMsgText());
                Multipart mp = new MimeMultipart();
                mp.addBodyPart(mbp1);

                BodyPart mbp = new MimeBodyPart();
                String imgName = getFile().getFileName().substring(getFile().getFileName().lastIndexOf("\\") + 1);
                System.out.println("file path: " + getFile().getFileName());
                DataSource src = new FileDataSource(getFile().getFileName());
                mbp.setDataHandler(new DataHandler(src));
                mbp.setFileName(imgName);
                mp.addBodyPart(mbp);
                message.setContent(mp);

            } else {
                message.setText(getMsgText());
            }

// Saving Draft
            Store store = mySession.getStore("imaps");
            store.connect("imap.gmail.com", getUsername(), getEmailPassword());
            Folder f = store.getFolder("[Gmail]/Drafts");
            f.open(Folder.READ_WRITE);
            Message m[] = new Message[1];
            m[0] = message;
            f.appendMessages(m);

            setStatus("Message Saved in 'Drafts'.");
            statusUpdate(getStatus());
// Empty inserted values by user
            emptyFields();

        } catch (Exception e) {
            setStatus(e.getMessage());
            e.printStackTrace();
    }
    }

    public String getRecipientsTo() {

        try {

            Address[] to = selectedMessage.getRecipients(Message.RecipientType.TO);
            for (int i = 0; i < to.length; i++) {
                if (i == 0) {
                    setTo(to[i].toString());
                } else {
                    setTo(getTo() + ";" + to[i].toString());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return getTo();
    }

    public String getRecipientsCc() {

        try {

            Address[] cc = selectedMessage.getRecipients(Message.RecipientType.CC);
            if (cc != null) {

                for (int j = 0; j < cc.length; j++) {
                    if (j == 0) {
                        setCc(cc[j].toString());
                    } else {
                        setCc(getCc() + ";" + cc[j].toString());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return getCc();
    }

//    public void handleFileUpload(FileUploadEvent event) {
//        logger.info("Uploaded: {}", event.getFile().getFileName());
//
//        FacesMessage msg = new FacesMessage("Succesful", event.getFile().getFileName() + " is uploaded.");
//        FacesContext.getCurrentInstance().addMessage(null, msg);
//    }
    public String getSender() {
        return getCurrentUser().getContact().getEmail();
    }

    public void setSender(String sender) {
        this.sender = sender;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getCc() {
        return cc;
    }

    public void setCc(String cc) {
        this.cc = cc;
    }

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getMsgText() {
        return msgText;
    }

    public void setMsgText(String msgText) {
        this.msgText = msgText;
    }

    public UploadedFile getFile() {
        return file;
    }

    public void setFile(UploadedFile file) {
        this.file = file;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getUsername() {
        return getCurrentUser().getContact().getEmail();
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
    }

    public boolean isLogin() {
        return login;
    }

    public void setLogin(boolean login) {
        this.login = login;
    }

    public ArrayList<Message> getMsg() {
        return msg;
    }

    public void setMsg(ArrayList<Message> msg) {
        this.msg = msg;
    }

    public Message getSelectedMessage() {
        return selectedMessage;
    }

    public void setSelectedMessage(Message selectedMessage) {
        this.selectedMessage = selectedMessage;
    }

    public String prepareReply() {
        try {
            setSender(getCurrentUser().getContact().getEmail());
            setTo((selectedMessage.getFrom())[0].toString());
            setSubject("RE: " + selectedMessage.getSubject());
            setMsgText("<br><br> _____________________________________________________ <br><br>" + selectedMessage.getContent().toString());
            setCc("");
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "email?faces-redirect=true";
    }

    public String prepareReplyAll() {
        try {
            setSender(getCurrentUser().getContact().getEmail());
            setTo((selectedMessage.getFrom())[0].toString());
            setSubject("RE: " + selectedMessage.getSubject());
            setMsgText("<br><br> _____________________________________________________ <br><br>" + selectedMessage.getContent().toString());
            setCc((getRecipientsCc()));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return "email?faces-redirect=true";
    }

    public String prepareForward() {
        try {
            setSender(getCurrentUser().getContact().getEmail());
            setTo("");
            setSubject("FWD: " + selectedMessage.getSubject());
            setMsgText("<br><br> _____________________________________________________ <br><br>" + selectedMessage.getContent().toString());
            setCc("");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "email?faces-redirect=true";
    }
    
    public String addFromAddressBook() {
        for (int i = 0; i < contactEntityController.getAddressBook().getTarget().size(); i++) {
            setTo(contactEntityController.getAddressBook().getTarget().get(i) + ";" + getTo());
        }
        return "email?faces-redirect=true";
    }
    
    public String addFromAddressBookCc() {
        
        for (int i = 0; i < contactEntityController.getAddressBookCc().getTarget().size(); i++) {
            setCc(contactEntityController.getAddressBookCc().getTarget().get(i) + ";" + getCc());
        }
        return "email?faces-redirect=true";
    }

    public ContactEntityController getContactEntityController() {
        return contactEntityController;
    }

    public void setContactEntityController(ContactEntityController contactEntityController) {
        this.contactEntityController = contactEntityController;
    }

    public String getEmailPassword() {
        emailPassword = loginBacking.getPassword();
        return emailPassword;
    }

    public void setEmailPassword(String emailPassword) {
        this.emailPassword = emailPassword;
    }

    public LoginBacking getLoginBacking() {
        return loginBacking;
    }

    public void setLoginBacking(LoginBacking loginBacking) {
        this.loginBacking = loginBacking;
    }
    
    public boolean checkSystemUser() {
        if (getCurrentUser() instanceof SystemUserEntity) {
            return true;
        }
        return false;
    }
    
}
